#pragma once

#include <common.h>
#include <ir/block.h>
#include <ir/reg.h>
#include <riscv/visitor.h>
#include <ir/global_reg.h>
#include <ir/ir.h>

#define DEF_INST(INST, ...) \
  class INST : public Inst { \
  public: \
    __VA_ARGS__; \
    virtual ~INST() = default; \
    virtual void print_get(std::string & str) override; \
    virtual void accept(riscv::Visitor & visitor) override; \
  }

namespace riscv {
  class Visitor;
}

namespace ir {
  class Func;
  class Block;
}

namespace ir {

  class Inst {
  public:
    virtual ~Inst();

    virtual void print_get(std::string & str) = 0;
    virtual void accept(riscv::Visitor & visitor) = 0;
  };

  DEF_INST(
      InstImm,
      // Must be i32 or f32
      VarType type;
      union {
        int int_number;
        float float_number;
      };
      Reg * reg;
    );

  DEF_INST(InstAlloc, Reg * reg; uint32_t size;);
  DEF_INST(InstStore, Reg * rd; Reg * src;);
  DEF_INST(InstLoad, Reg * rd; Reg * src;);
  DEF_INST(InstArrayAlloc, Reg * reg; uint32_t size; uint32_t count;);
  DEF_INST(InstArrayStore, Reg * rd; Reg * src; Reg * index;);
  DEF_INST(InstArrayLoad, Reg * rd; Reg * src; Reg * index;);
  DEF_INST(InstGlobalAlloc, GlobalReg * global_reg; uint32_t size; VarType type;
      union {int int_number; float float_number;};);
  DEF_INST(InstGlobalStore, GlobalReg * global_rd; Reg * src;);
  DEF_INST(InstGlobalLoad, Reg * rd; GlobalReg * global_src;);

  DEF_INST(InstI32ToF32, Reg * rd; Reg * src;);
  DEF_INST(InstF32ToI32, Reg * rd; Reg * src;);

  DEF_INST(InstCall, Reg * rd; Func * func; std::vector<Reg*> args;);
  DEF_INST(InstRet, VarType type; Reg * reg;);

  DEF_INST(InstAdd, Reg * rd; Reg * src1; Reg * src2;);
  DEF_INST(InstSub, Reg * rd; Reg * src1; Reg * src2;);
  DEF_INST(InstMul, Reg * rd; Reg * src1; Reg * src2;);
  DEF_INST(InstDiv, Reg * rd; Reg * src1; Reg * src2;);

  DEF_INST(InstJmp, Block * block);
  DEF_INST(InstBne, Reg * src1; Reg * src2; Block * block;);
  DEF_INST(InstBeq, Reg * src1; Reg * src2; Block * block;);
}

#undef DEF_INST
